from appserver import db_store, execute_sql, sql_row_to_dict
from sqlalchemy import or_, update
from sqlalchemy import func
import copy

from utils.result import result


class TreeModelBase(db_store.Model):
    __abstract__ = True  # 使TreeModelBase不必与数据表关联

    id = db_store.Column(db_store.Integer, primary_key=True, comment=u'ID', )
    parent_id = db_store.Column(db_store.Integer, nullable=False, comment=u"父ID")
    path = db_store.Column(db_store.String(255), nullable=False, comment=u"路径")
    depth = db_store.Column(db_store.Integer, comment=u"深度")
    child_num = db_store.Column(db_store.Integer, comment=u"子类数量", default=0)
    dis_order = db_store.Column(db_store.Integer, comment=u"排序")

    def __init__(self):
        self.id = 0
        self.parent_id = 0
        self.dis_order = 0
        self.depth = 0
        self.child_num = 0

    def from_dict(self, rev_source):
        source = copy.deepcopy(rev_source)
        # print('source', source)
        # if "parent_id" in source:
        # Instance '<District at 0x7f28901badd8>' has been deleted, or its row is otherwise not present.
        # 下面的方法引起的错误
        # source["parent_id"] = source.pop("parent_id") #
        # source["parent_id"] = source.get("parent_id")
        if "level" in source:
            source["depth"] = source.pop("level")
        if "children" in source:
            source.pop("children")
        for k in source:
            # print('k',k)
            try:
                getattr(self, k)
                # print('getattr',getattr(self, k))
            except AttributeError as e:
                print(e)
                raise RuntimeError("数据格式错误")
            setattr(self, k, source[k])
            # print('setattr',setattr(self, k, source[k]))

    def to_dict(self):
        rdic = {}
        for c in self.__table__.columns:
            if c.name == "parent_id":
                # rdic["ParentId"] = getattr(self, c.name, None)
                rdic["parent_id"] = getattr(self, c.name, None)
            elif c.name == "depth":
                # rdic["Level"] = getattr(self, c.name, None)
                rdic["level"] = getattr(self, c.name, None)
            else:
                rdic[c.name] = getattr(self, c.name, None)
        return rdic

    def get_max_id(self):
        val = db_store.session.query(func.max(self.__class__.id)).scalar()
        if not val:
            return 0
        else:
            return val

    def update(self):
        try:
            # if self.id == 0:  # 新增数据
            #     self.id = self.get_max_id() + 1
            print('(((((up')
            db_store.session.add(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print(')))))')
            print(err)
            db_store.session.rollback()
            return False

    def save1(self):
        try:
            # if self.id == 0:  # 新增数据
            #     self.id = self.get_max_id() + 1
            print('(((((')
            db_store.session.add(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print(')))))')
            print(err)
            db_store.session.rollback()
            return False

        """
        old_parent_sql = "select * from " + self.__table__.name + " where id = " + str(self.id)
                old_parent = sql_row_to_dict(execute_sql(old_parent_sql))
                old_parent_id = old_parent["parent_id"]
                print(old_parent_id)
        """

    """
    def save(self):
        # 原先的方法
        try:
            if self.id == 0:  # 新增数据
                self.id = self.get_max_id() + 1
                if self.parent_id == 0:  # 添加为一级节点
                    self.path = str(self.id)
                    self.depth = 1
                    self.child_num = 0
                else:
                    parent_entity = copy.deepcopy(self.get_entity_by_id(self.parent_id))  # 获取父节点
                    self.path = parent_entity.path + ',' + str(self.id)
                    self.depth = len(self.path.split(','))
                    self.child_num = 0
                    parent_entity.child_num = parent_entity.child_num + 1
                    #parent_entity.save()
                    str1 = "update " + self.__table__.name + " set child_num = " + str(parent_entity.child_num) + " where id = " + str(parent_entity.id)
                    execute_sql(str1)
            else:  # 更新数据
                old_parent_sql = "select * from " + self.__table__.name + " where id = " + str(self.id)
                old_parent = sql_row_to_dict(execute_sql(old_parent_sql))
                old_parent_id = old_parent["parent_id"]
                print(old_parent_id)

                entity = copy.deepcopy(self.get_entity_by_id(self.id))  # 获取旧数据用于判断是否更换了父节点
                old_parent_entity = copy.deepcopy(self.get_entity_by_id(old_parent_id))
                print('old_parent_entity', old_parent_entity)
                new_parent_entity = copy.deepcopy(self.get_entity_by_id(self.parent_id))  # 获取父节点数据
                print('self.parent_id ', self.parent_id, 'old_parent_entity.id:', old_parent_entity.id)
                if self.parent_id != old_parent_id:  # 判断是否更换了父ID
                    if str(self.id) in new_parent_entity.path.split(','):  # 判断是否移动到自己的子节点下
                        raise RuntimeError("不能移动到自己的子节点下")
                    self.path = new_parent_entity.path + ',' + str(self.id)  # 更新自己的path
                    self.depth = len(self.path.split(','))  # 更新自己的深度
                    if not (old_parent_entity is None):  # 判断旧的父节点是否为空，也就是原来是不是最顶层的模块
                        old_parent_entity.child_num = old_parent_entity.child_num - 1
                        # old_parent_entity.save()

                        str1 = "update " + self.__table__.name + " set child_num = " + str(
                            old_parent_entity.child_num) + " where id = " + str(old_parent_entity.id)
                        execute_sql(str1)
                    new_parent_entity.child_num = new_parent_entity.child_num + 1  # 父节点的子节点数减去1
                    # parent_entity.save()

                    str1 = "update " + self.__table__.name + " set child_num = " + str(
                        new_parent_entity.child_num) + " where id = " + str(new_parent_entity.id)
                    execute_sql(str1)
                    # 获取所有深度的子节点
                    print(1111)
                    # SELECT * FROM [user] WHERE u_name LIKE '%三%' AND u_name LIKE '%猫%'
                    # str2 = "select * from " + self.__table__.name + " where  = " + str(self.id)
                    nodes = self.query.filter(
                        or_(self.path.like(entity.path + ',%'), self.path.like('%,' + entity.path + ',%')))
                    print('node', nodes)
                    print(2222)
                    for item in nodes:
                        item.path = item.path.replace(entity.path, self.path)
                        item.depth = len(item.path.split(','))
                        item.save()
            db_store.session.add(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print('保存错误了')
            print(err)
            db_store.session.rollback()
            return False
    """
    """
    def save(self, *args):
        try:
            if self.id == 0:  # 新增数据
                self.id = self.get_max_id() + 1
                if self.parent_id == 0:  # 添加为一级节点
                    self.path = str(self.id)
                    self.depth = 1
                    self.child_num = 0
                else:
                    parent_entity = self.get_entity_by_id(self.parent_id)  # 获取父节点
                    print('前parent_entity.child_num', parent_entity.child_num)
                    parent_entity.child_num = parent_entity.child_num + 1
                    print('后parent_entity.child_num', parent_entity.child_num)
                    self.path = parent_entity.path + ',' + str(self.id)
                    self.depth = len(self.path.split(','))
                    self.child_num = 0
                    # parent_entity.save()
                    str1 = "update " + self.__table__.name + " set child_num = " + str(
                        parent_entity.child_num) + " where id = " + str(parent_entity.id)

                    execute_sql(str1)

            else:  # 更新数据
                print('更新数据')
                old_entity = self.get_entity_by_id(self.id)  # 获取旧数据用于判断是否更换了父节点  id=2
                old_parent_entity = self.get_entity_by_id(*args)  # 旧的父节点  id=1
                parent_entity = self.get_entity_by_id(self.parent_id)  # 获取新的父节点数据
                # old_entity.save()
                print('self.parent_id ', self.parent_id , 'old_parent_entity.id:', old_parent_entity.id)
                if self.parent_id != old_parent_entity.id:  # 判断是否更换了父ID  跟换了父节点
                    if str(self.id) in parent_entity.path.split(','):  # 判断是否移动到自己的子节点下 8 > 1,2
                        raise RuntimeError("不能移动到自己的子节点下")
                    self.path = parent_entity.path + ',' + str(self.id)  # 更新自己的path  1,10
                    self.depth = len(self.path.split(','))  # 更新自己的深度
                    if not (old_parent_entity is None):  # 判断旧的父节点是否为空，也就是原来是不是最顶层的模块
                        old_parent_entity.child_num = old_parent_entity.child_num - 1

                        str1 = "update " + self.__table__.name + " set child_num = " + str(
                            old_parent_entity.child_num) + " where id = " + str(old_parent_entity.id)

                        execute_sql(str1)
                        # old_parent_entity.update()
                        # old_parent_entity.save1()
                    # parent_entity = update(parent_entity).where()
                    parent_entity.child_num = parent_entity.child_num + 1  # 父节点的子节点数加上1

                    str1 = "update " + self.__table__.name + " set child_num = " + str(
                        parent_entity.child_num) + " where id = " + str(parent_entity.id)

                    execute_sql(str1)
                    # parent_entity.save()
                    # parent_entity.update()
                    # 获取所有深度的子节点
                    nodes = self.query.filter(
                        or_(self.path.like(old_entity.path + ',%'), self.path.like('%,' + old_entity.path + ',%')))
                    print(1111111111111111)
                    for item in nodes:
                        item.path = item.path.replace(old_entity.path, self.path)
                        item.depth = len(item.path.split(','))
                        item.save()
                    print(2222222222222222)
            db_store.session.add(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print('保存错误了,死俏皮哦')
            print(err)
            db_store.session.rollback()
            return False
    """

    def delete(self):
        try:
            print('delete')
            if self.child_num > 0:
                raise RuntimeError("存在子节点，请先删除子节点.")
                # return result(success=0, error_code=-3, error_msg="存在子节点，请先删除子节点.")
            parent_entity = self.get_entity_by_id(self.parent_id)  # 更新(查询)父节点
            print('parent_entity', parent_entity)
            if not (parent_entity is None):  # 判断旧的父节点是否为空，也就是原来是不是最顶层的模块(如果不为空)
                #  删除了一个子节点,所以他的父节点的child_num应该减1
                print('if not (parent_entity is None)')
                parent_entity.child_num = parent_entity.child_num - 1
                parent_entity.save()
                # str1 = "update " + self.__table__.name + " set child_num = " + str(
                #     parent_entity.child_num) + " where id = " + str(parent_entity.id)
                # execute_sql(str1)

            db_store.session.delete(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print(err)
            db_store.session.rollback()
            return False

    def get_list_all(self):
        return self.query.all()

    def get_list_by_pid(self, pid):
        return self.query.filter_by(parent_id=pid).all()

    def get_entity_by_id(self, id):
        # print(555555555,copy.deepcopy(self.query.filter_by(id=id).first()))
        return copy.deepcopy(self.query.filter_by(id=id).first())

    def get_left_tree(self, pid):
        """
        根据父ID返回模块树
        :param pid: 父ID
        :return: list
        """

        result = []
        try:
            nodes = self.query.filter_by(parent_id=pid).order_by(db_store.desc("dis_order")).all()
            # print('nodes:',nodes)
            for item in nodes:
                tmp = item.to_dict()
                if item.child_num > 0:
                    tmp['children'] = self.get_left_tree(item.id)  # 这个用到递归,所以会遍历所以的子节点
                result.append(tmp)
            return result
        except Exception as err:
            print(err)
            return []

    def get_tree_by_pid(self, pid):
        """
        根据父ID返回模块树
        :param pid: 父ID
        :return: list
        """
        result = []
        try:
            nodes = self.query.filter_by(parent_id=pid).order_by(db_store.desc("dis_order")).all()
            # print('nodes111:', nodes)
            for item in nodes:
                # print('item111:', item)
                tmp = item.to_dict()
                result.append(tmp)
                if self.query.filter_by(parent_id=item.id).first():
                    if item.child_num > 0:  # 这个方法本来是正确的,但是数据库的child_num数据错乱,所以不得以调用下面的方法
                        tmp['children'] = self.get_tree_by_pid(item.id)
            return result
        except Exception as err:
            print(err)
            return []

    def get_tree(self, pid):
        """
        根据父ID返回模块树
        :param pid: 父ID
        :return: list
        """

        result = []
        try:
            nodes = self.query.filter_by(parent_id=pid).order_by(db_store.desc("dis_order")).all()
            # print('nodes:', nodes)
            for item in nodes:
                # print('item:', item)
                tmp = item.to_dict()
                result.append(tmp)
                if self.query.filter_by(parent_id=item.id).first():
                    # if item.child_num > 0:
                    tmp['children'] = self.get_tree(item.id)
            return result
        except Exception as err:
            print(err)

            return []
    # 正确的写法
    def save(self):
        try:
            if self.id == 0:  # 新增数据
                self.parent_id = int(self.parent_id)
                self.id = self.get_max_id() + 1
                if self.parent_id == 0:  # 添加为一级节点
                    self.path = str(self.id)
                    self.depth = 1
                    self.child_num = 0
                else:
                    parent_entity = self.get_entity_by_id(self.parent_id)  # 获取父节点数据
                    self.path = parent_entity.path + ',' + str(self.id)
                    self.depth = len(self.path.split(','))
                    self.child_num = 0
                    parent_entity.child_num = parent_entity.child_num + 1
                    # parent_entity.save()
                    str1 = "update " + self.__table__.name + " set child_num = " + str(
                        parent_entity.child_num) + " where id = " + str(parent_entity.id)
                    execute_sql(str1)

            else:  # 更新数据
                print('else')
                old_entity = self.get_entity_by_id(self.id)  # 获取旧数据用于判断是否更换了父节点
                print('自己', old_entity)
                old_parent_entity = self.get_entity_by_id(old_entity.parent_id)
                print('旧父类', old_parent_entity)

                ###
                if self.parent_id == 0:
                    if self.parent_id != old_entity.parent_id:
                        # parent_entity = copy.deepcopy(self.query.filter_by(id=id).first())
                        self.path = str(self.id)
                        self.depth = len(self.path.split(','))
                        # str1 = "update " + self.__table__.name + " set path = " + str(
                        #     self.id) + " where id = " + str(self.id)
                        # execute_sql(str1)
                        if not (old_parent_entity is None):  # 判断旧的父节点是否为空，也就是原来是不是最顶层的模块
                            old_parent_entity.child_num = old_parent_entity.child_num - 1
                            old_parent_entity.save()
                        nodes = self.query.filter(
                            or_(self.__class__.path.like(old_entity.path + ',%'),
                                self.__class__.path.like('%,' + old_entity.path + ',%')))
                        for item in nodes:
                            item.path = item.path.replace(old_entity.path, self.path)
                            item.depth = len(item.path.split(','))
                            item.save()


                ####
                else:
                    parent_entity = self.get_entity_by_id(self.parent_id)  # 获取父节点数据
                    if self.parent_id != old_entity.parent_id:  # 判断是否更换了父ID
                        if str(self.id) in parent_entity.path.split(','):  # 判断是否移动到自己的子节点下
                            # return result(success=0, error_code=-6, error_msg="不能移动到自己的子节点下")
                            raise RuntimeError("不能移动到自己的子节点下")
                        self.path = parent_entity.path + ',' + str(self.id)  # 更新自己的path
                        self.depth = len(self.path.split(','))  # 更新自己的深度
                        if not (old_parent_entity is None):  # 判断旧的父节点是否为空，也就是原来是不是最顶层的模块
                            old_parent_entity.child_num = old_parent_entity.child_num - 1
                            old_parent_entity.save()
                        parent_entity.child_num = parent_entity.child_num + 1  # 父节点的子节点数减去1
                        parent_entity.save()
                        pass  # 获取所有深度的子节点
                        nodes = self.query.filter(
                            or_(self.__class__.path.like(old_entity.path + ',%'), self.__class__.path.like('%,' + old_entity.path + ',%')))
                        for item in nodes:
                            item.path = item.path.replace(old_entity.path, self.path)
                            item.depth = len(item.path.split(','))
                            item.save()
            db_store.session.add(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print(err)
            db_store.session.rollback()
            return False
